<script setup lang="ts">
import type { AppTypeProps } from '@/types';

import { onBeforeMount, onMounted, type PropType, ref } from 'vue';

import { ElButton, ElMessage } from 'element-plus';

defineOptions({
  name: 'HomeWeb',
});

defineProps({
  app: {
    default: () => ({}),
    type: Object as PropType<AppTypeProps>,
  },
});
const canUse = ref(false);
const width = ref(540);
const height = ref(405);
const mode = ref('portrait');
const nowPreview = ref('');
const shootedList = ref<string[]>([]);
const videoElRef = ref();
const canvasElRef = ref();

const base64Img2Blob = (code: string) => {
  const parts = code.split(';base64,');
  const contentType = parts[0]?.split(':')[1];
  const raw = window.atob(parts[1] as string);
  const rawLength = raw.length;

  const uInt8Array = new Uint8Array(rawLength);

  for (let i = 0; i < rawLength; ++i) {
    uInt8Array[i] = raw.codePointAt(i) as number;
  }

  return new Blob([uInt8Array], { type: contentType });
};
const download = () => {
  const canvasID = canvasElRef.value;
  const download = document.createElement('a');
  const blob = base64Img2Blob(canvasID.toDataURL('image/png'));
  const url = URL.createObjectURL(blob);
  download.setAttribute('href', url);
  download.setAttribute('download', `${Date.now()}.png`);
  document.body.append(download);
  download.click();
  URL.revokeObjectURL(url);
  download.remove();
};
const getCamera = () => {
  // 这段代 主要是获取摄像头的视频流并显示在Video 签中
  const video = videoElRef.value;
  window.URL = window.URL || window.webkitURL;

  // Call the getUserMedia method with our callback functions
  if (navigator.mediaDevices.getUserMedia) {
    canUse.value = true;
    navigator.mediaDevices
      .getUserMedia({ video: true })
      .then((stream) => {
        // Set the source of the video element with the stream from the camera
        if (video.mozSrcObject === undefined) {
          video.srcObject = stream;
        } else {
          video.mozSrcObject = stream;
        }
        video.play();
      })
      .catch((error) => {
        ElMessage.error(`错误代码: [CODE ${error.code}]`);
      });
  } else {
    ElMessage.error('浏览器不支持getUserMedia方法调用摄像头');
    // Display a friendly "sorry" message to the user
  }
};
const preview = (photo: string) => {
  nowPreview.value = photo;
};
const shoot = () => {
  if (nowPreview.value) {
    nowPreview.value = '';
    return;
  }
  const content = canvasElRef.value?.getContext('2d');
  const video = videoElRef.value;
  content.drawImage(video, 0, 0, 540, 405);
  // 获取浏览器页面的画布对象
  const canvas = canvasElRef.value;
  // 以下开始编码数据
  const imgData = canvas?.toDataURL() || '';
  // 将获得的base64数据加入shootedList数组
  shootedList.value.push(imgData);
};
const deletePhoto = (index: number) => {
  const _shootedList = shootedList.value;
  _shootedList?.splice(index, 1);
  shootedList.value = _shootedList;
  if (nowPreview.value && _shootedList?.length === 0) {
    shoot();
  }
};
onMounted(() => {
  try {
    getCamera();
  } catch (error) {
    window.console.log(error);
  }
});
onBeforeMount(() => {
  try {
    const stream = videoElRef.value.srcObject;
    const tracks = stream.getTracks();
    tracks.forEach((track: MediaStreamTrack) => {
      track.stop();
    });
    videoElRef.value.srcObject = null;
  } catch (error) {
    window.console.log('关闭摄像头异常', error);
  }
});
</script>

<template>
  <div class="demo">
    <div class="preview">
      <video ref="videoElRef" :width="width"></video>
      <div v-if="nowPreview" class="shooted-preview">
        <img
          :src="`data:image/png;base64,${nowPreview}`"
          class="shooted-preview-photo"
        />
      </div>
      <div
        v-if="shootedList.length > 0"
        :style="nowPreview ? `top: -${height}px` : 'top: -60px'"
        class="shooted-list"
      >
        <div
          v-for="(photo, index) in shootedList"
          :key="photo"
          style="display: inline-block"
        >
          <div class="shooted-del">
            <i class="el-icon-error" @click="deletePhoto(index)"></i>
          </div>
          <img
            :src="`data:image/png;base64,${photo}`"
            class="photo"
            @click="preview(photo)"
          />
        </div>
      </div>
    </div>
    <div v-if="canUse" class="toolbar">
      <el-radio-group
        v-model="mode"
        :style="nowPreview ? 'visibility:hidden;' : ''"
        fill="#A0A0A0"
        size="small"
        text-color="#fff"
      >
        <el-radio-button label="fourPhoto">
          <i class="el-icon-menu"></i>
        </el-radio-button>
        <el-radio-button label="portrait">
          <i class="el-icon-s-custom"></i>
        </el-radio-button>
        <el-radio-button label="video">
          <i class="el-icon-video-camera"></i>
        </el-radio-button>
      </el-radio-group>
      <div class="tool-action">
        <el-avatar
          :class="nowPreview ? 'back-shoot' : 'shoot-btn'"
          @click="shoot"
        >
          <i class="iconfont icon-camera_fill shoot-icon"></i>
        </el-avatar>
      </div>
      <ElButton v-if="!nowPreview" size="small">效果</ElButton>
      <ElButton v-else size="small" @click="download()">分享</ElButton>
      <canvas
        ref="canvasElRef"
        :height="height"
        :width="width"
        style="display: none"
      ></canvas>
    </div>
    <div v-else class="title">浏览器不支持</div>
  </div>
</template>
<style scoped>
.demo {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  margin-top: 0;
  color: #333;
  text-shadow: none;
}

.preview {
  width: 540px;
  height: 405px;
}

.shooted-preview {
  position: relative;
  bottom: 405px;
  z-index: 1;
  width: 540px;
  height: 345px;
  background-color: #000;
  background-repeat: no-repeat;
}

.shooted-preview-photo {
  width: 540px;
  height: 405px;
}

.shooted-del {
  position: relative;
  top: 0;
  left: 0;
  z-index: 3;
  width: 3px;
  height: 3px;
}

.toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 540px;
  height: 50px;
  margin: 10px;
}

.shooted-list {
  position: relative;
  bottom: 60px;
  z-index: 2;
  width: 535px;
  height: 60px;
  overflow: scroll hidden;
  text-align: right;
  white-space: nowrap;
  background-color: #f4e5ecf7;
}

.shoot-btn {
  background-color: red;
}

.back-shoot {
  background-color: gray;
}

.tool-action {
  width: 130px;
}

.shoot-icon {
  font-size: 24px;
  color: white;
}

.photo {
  width: 50px;
  height: 50px;
  margin: 5px;
  background-color: #000;
  background-repeat: no-repeat;
}

.title {
  margin: 10%;
  font-size: 24px;
  text-align: left;
}
</style>
